package com.dkd.manage.task.allocator.service;

import com.dkd.manage.domain.Emp;
import com.dkd.manage.domain.VendingMachine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

@Slf4j
@Service
public class DistanceCalculator {

    public double calculateDistance(Emp emp, VendingMachine machine) {
        // 检查位置信息是否完整
        if (!hasValidLocation(emp) || !hasValidLocation(machine)) {
            log.debug("位置信息不完整，使用默认距离");
            return 5.0; // 默认距离
        }

        try {
            // 将 BigDecimal 转换为 double
            double lat1 = convertToDouble(emp.getLatitude());
            double lon1 = convertToDouble(emp.getLongitude());
            double lat2 = convertToDouble(BigDecimal.valueOf(machine.getLatitude()));
            double lon2 = convertToDouble(BigDecimal.valueOf(machine.getLongitudes()));

            // 使用Haversine公式计算地球表面距离
            return calculateHaversineDistance(lat1, lon1, lat2, lon2);

        } catch (Exception e) {
            log.error("计算距离异常: {}", e.getMessage());
            return 5.0;
        }
    }

    /**
     * 将 BigDecimal 安全地转换为 double
     */
    private double convertToDouble(BigDecimal value) {
        if (value == null) {
            throw new IllegalArgumentException("坐标值不能为null");
        }
        return value.doubleValue();
    }

    /**
     * 检查是否有有效的位置信息
     */
    private boolean hasValidLocation(Emp emp) {
        return emp != null &&
                emp.getLatitude() != null &&
                emp.getLongitude() != null;
    }

    /**
     * 检查是否有有效的位置信息
     */
    private boolean hasValidLocation(VendingMachine machine) {
        return machine != null &&
                machine.getLatitude() != null &&
                machine.getLongitudes() != null;
    }

    /**
     * 使用Haversine公式计算距离
     */
    private double calculateHaversineDistance(double lat1, double lon1, double lat2, double lon2) {
        // 将角度转换为弧度
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);

        // 经纬度差值
        double dLat = lat2Rad - lat1Rad;
        double dLon = lon2Rad - lon1Rad;

        // Haversine公式
        double a = Math.pow(Math.sin(dLat / 2), 2)
                + Math.cos(lat1Rad) * Math.cos(lat2Rad)
                * Math.pow(Math.sin(dLon / 2), 2);

        double c = 2 * Math.asin(Math.sqrt(a));

        // 地球半径（公里）
        double earthRadius = 6371;

        double distance = c * earthRadius;

        log.debug("计算距离: ({}, {}) -> ({}, {}) = {}公里",
                lat1, lon1, lat2, lon2, distance);

        return distance;
    }

    /**
     * 计算距离等级（0-1之间的值，越小表示距离越近）
     */
    public double calculateDistanceLevel(double distance) {
        if (distance <= 1.0) return 0.1;  // 很近
        if (distance <= 3.0) return 0.3;  // 较近
        if (distance <= 5.0) return 0.5;  // 中等
        if (distance <= 10.0) return 0.7; // 较远
        return 0.9; // 很远
    }

    /**
     * 计算距离等级（基于员工和设备）
     */
    public double calculateDistanceLevel(Emp emp, VendingMachine machine) {
        double distance = calculateDistance(emp, machine);
        return calculateDistanceLevel(distance);
    }

    /**
     * 获取距离描述
     */
    public String getDistanceDescription(double distance) {
        if (distance <= 1.0) return "很近";
        if (distance <= 3.0) return "较近";
        if (distance <= 5.0) return "中等";
        if (distance <= 10.0) return "较远";
        return "很远";
    }

    /**
     * 检查是否在合理距离范围内（例如10公里内）
     */
    public boolean isWithinReasonableDistance(Emp emp, VendingMachine machine, double maxDistance) {
        double distance = calculateDistance(emp, machine);
        return distance <= maxDistance;
    }

    /**
     * 获取最佳路径距离（考虑实际道路情况，这里简化为直线距离的1.3倍）
     */
    public double calculateRouteDistance(Emp emp, VendingMachine machine) {
        double straightDistance = calculateDistance(emp, machine);
        // 假设实际道路距离是直线距离的1.3倍
        return straightDistance * 1.3;
    }

    /**
     * 估算行程时间（分钟）
     */
    public double estimateTravelTime(Emp emp, VendingMachine machine, double averageSpeed) {
        double routeDistance = calculateRouteDistance(emp, machine);
        // 时间 = 距离 / 速度 * 60（转换为分钟）
        return (routeDistance / averageSpeed) * 60;
    }

    /**
     * 获取行程时间描述
     */
    public String getTravelTimeDescription(double travelTimeMinutes) {
        if (travelTimeMinutes < 10) return "很快到达";
        if (travelTimeMinutes < 30) return "较快到达";
        if (travelTimeMinutes < 60) return "需要一些时间";
        return "需要较长时间";
    }

    /**
     * 计算距离得分（用于评分系统，距离越近得分越高）
     */
    public double calculateDistanceScore(Emp emp, VendingMachine machine) {
        double distance = calculateDistance(emp, machine);

        // 距离越近得分越高，最高10分
        if (distance <= 1.0) return 10.0;
        if (distance <= 3.0) return 8.0;
        if (distance <= 5.0) return 6.0;
        if (distance <= 8.0) return 4.0;
        if (distance <= 12.0) return 2.0;
        return 1.0;
    }

    /**
     * 批量计算距离（优化性能）
     */
    public java.util.Map<Long, Double> calculateDistancesToMachines(Emp emp, java.util.List<VendingMachine> machines) {
        java.util.Map<Long, Double> distances = new java.util.HashMap<>();

        for (VendingMachine machine : machines) {
            double distance = calculateDistance(emp, machine);
            distances.put(machine.getId(), distance);
        }

        return distances;
    }

    /**
     * 找到最近的设备
     */
    public VendingMachine findNearestMachine(Emp emp, java.util.List<VendingMachine> machines) {
        if (machines == null || machines.isEmpty()) {
            return null;
        }

        VendingMachine nearest = null;
        double minDistance = Double.MAX_VALUE;

        for (VendingMachine machine : machines) {
            double distance = calculateDistance(emp, machine);
            if (distance < minDistance) {
                minDistance = distance;
                nearest = machine;
            }
        }

        return nearest;
    }

    /**
     * 验证坐标是否在合理范围内
     */
    public boolean isValidCoordinate(BigDecimal latitude, BigDecimal longitude) {
        if (latitude == null || longitude == null) {
            return false;
        }

        double lat = latitude.doubleValue();
        double lon = longitude.doubleValue();

        // 中国大致经纬度范围
        return lat >= 3.0 && lat <= 53.0 && lon >= 73.0 && lon <= 135.0;
    }

    /**
     * 获取坐标字符串
     */
    public String getCoordinateString(BigDecimal latitude, BigDecimal longitude) {
        if (latitude == null || longitude == null) {
            return "未知坐标";
        }
        return String.format("(%.6f, %.6f)", latitude.doubleValue(), longitude.doubleValue());
    }
}